package com.kalua.list.dbaccess.user;

import static com.datastax.driver.core.querybuilder.QueryBuilder.eq;
import static com.datastax.driver.core.querybuilder.QueryBuilder.in;
import static com.datastax.driver.core.querybuilder.QueryBuilder.set;
import static com.kalua.list.dbaccess.DAOConstants.ACCOUNT_REF_COLUMN_NAME;
import static com.kalua.list.dbaccess.user.UserRowMapper.COUNTRY_CODE_COL_NAME;
import static com.kalua.list.dbaccess.user.UserRowMapper.EMAIL_COLUMN_NAME;
import static com.kalua.list.dbaccess.user.UserRowMapper.PHONE_NUMBER_COL_NAME;
import static com.kalua.list.dbaccess.user.UserRowMapper.PREF_NAME_COL_NAME;
import static com.kalua.list.dbaccess.user.UserRowMapper.USER_COL_FAMILY_NAME;
import static com.kalua.list.dbaccess.user.UserRowMapper.VERIFIED_COL_NAME;
import static java.util.stream.Collectors.toList;

import java.util.Collection;

import org.springframework.cassandra.core.RowMapper;
import org.springframework.data.cassandra.core.CassandraTemplate;

import com.datastax.driver.core.Statement;
import com.datastax.driver.core.querybuilder.Insert;
import com.datastax.driver.core.querybuilder.QueryBuilder;
import com.kalua.list.dbaccess.AbstractCRUDDAO;
import com.kalua.list.domainmodel.UUIDIdentifier;
import com.kalua.list.domainmodel.security.EmailAddress;
import com.kalua.list.domainmodel.security.User;

public class UserDAOImpl 	extends AbstractCRUDDAO<User, EmailAddress> 
												implements UserDAO {
	
	public UserDAOImpl(CassandraTemplate template) { super(template); }

	@Override
	public User readByAccountReference(UUIDIdentifier reference) {
		User result;		
		Statement statement = QueryBuilder.select().all()
		        							.from(USER_COL_FAMILY_NAME)
		        							.where(eq(ACCOUNT_REF_COLUMN_NAME, reference.getValue()));		
		result = executeSingleReturnSelect(statement);
		return result;
	}
	
	@Override
	protected RowMapper<User> getRowMapper() 
	{ return new UserRowMapper(); }
	
	@Override
	protected Insert buildInsertStatement(User user) {
		Insert insert = QueryBuilder.insertInto(USER_COL_FAMILY_NAME)
				.value(EMAIL_COLUMN_NAME, user.getId().getValue())
				.value(ACCOUNT_REF_COLUMN_NAME, user.getAccountReference().getValue())
				.value(PREF_NAME_COL_NAME, user.getPreferredName())
				.value(VERIFIED_COL_NAME, user.isVerified())
				.value(PHONE_NUMBER_COL_NAME, user.getPhoneNumber().toNeutralString())
				.value(COUNTRY_CODE_COL_NAME, user.getCountryOfResidence().getValue())				
				.ifNotExists();		
		return insert;
	}

	@Override
	protected Statement buildMultiRowSelect(Object[] keys) {
		Statement statement = QueryBuilder.select().all()
								.from(USER_COL_FAMILY_NAME)
								.where(in(EMAIL_COLUMN_NAME, keys));
		return statement;
	}

	@Override
	protected Statement buildReadAllStatement() {
		Statement statement = QueryBuilder.select().all()
												.from(USER_COL_FAMILY_NAME);
		return statement;
	}

	@Override
	protected Statement buildUpdateStatement(User user) {
		Statement update = QueryBuilder.update(USER_COL_FAMILY_NAME)
		        .with(set(PREF_NAME_COL_NAME, user.getPreferredName()))
				.and(set(VERIFIED_COL_NAME, user.isVerified()))
				.and(set(PHONE_NUMBER_COL_NAME, user.getPhoneNumber().toNeutralString()))
				.and(set(COUNTRY_CODE_COL_NAME, user.getCountryOfResidence().getValue()))					        		        
		        .where(eq(EMAIL_COLUMN_NAME, user.getId().getValue()))
		        .and(eq(ACCOUNT_REF_COLUMN_NAME, user.getAccountReference().getValue()));
		return update;
	}

	@Override
	protected Statement buildDeleteStatement(EmailAddress id) {
		Statement statement = QueryBuilder.delete()
		        .from(USER_COL_FAMILY_NAME)
		        .where(eq(EMAIL_COLUMN_NAME, id.getValue()));
		return statement;
	}
	
	@Override
	protected Object[] toObjectArray(Collection<EmailAddress> keys) {
		Object[] result = 
				keys.stream().map(n -> n.getValue()).collect(toList()).toArray();
		return result;
	}	

	@Override
	protected Statement buildReadStatement(EmailAddress id) {
		Statement statement = QueryBuilder.select().all()
		        							.from(USER_COL_FAMILY_NAME)
		        							.where(eq(EMAIL_COLUMN_NAME, id.getValue()));
		return statement;
	}	
}